package consistenthash

import (
	"hash/crc32"
	"sort"
	"strconv"
)

// Hasp map bytes to uint32
type Hash func(data []byte) uint32

// Map constains all hashed keys
type Map struct {
	hash Hash  // Hash函数
	replicas int  // 虚拟节点倍数
	keys []int  // 哈希环
	hashMap map[int]string // 虚拟节点与真实节点的映射表
}

// 创建一个Map实例
func NewMap(replicas int, fn Hash) *Map {
	m := &Map{
		hash:     fn,
		replicas: replicas,
		hashMap:  make(map[int]string),
	}
	if m.hash == nil{
		m.hash = crc32.ChecksumIEEE
	}
	return m
}

// 添加一些keys到hash, 允许传入0或者多个真实节点的名称
func (m *Map) Add(keys ...string){
	for _, key := range keys{
		for i := 0; i < m.replicas; i++ {
			hash := int(m.hash([]byte(strconv.Itoa(i) + key)))
			m.keys = append(m.keys, hash)
			m.hashMap[hash] = key
		}
	}
	sort.Ints(m.keys)
}

// 得到真实节点
func (m *Map) Get(key string) string{
	if len(m.keys) == 0{
		return ""
	}

	hash := int(m.hash([]byte(key)))
	idx := sort.Search(len(m.keys), func(i int) bool {
		return m.keys[i] >= hash
	})
	index := idx %len(m.keys)
	//fmt.Println(index)
	return m.hashMap[m.keys[index]]
}

